import { BadRequestException, Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as Minio from 'minio';
import { v4 as uuidv4 } from 'uuid';
/**
 * 文件上传服务
 *
 * 职责：
 * 1. 上传文件到 MinIO
 * 2. 生成文件访问 URL
 * 3. 删除文件
 * 4. 文件类型验证
 */
@Injectable()
export class UploadService {
  private minioClient: Minio.Client;
  private bucket: string;

  constructor(private configService: ConfigService) {
    // 初始化
    this.minioClient = new Minio.Client({
      endPoint: this.configService.get('minio.endPoint') || 'localhost',
      port: this.configService.get('minio.port') || 9000,
      useSSL: this.configService.get('minio.useSSL'),
      accessKey: this.configService.get('minio.accessKey'),
      secretKey: this.configService.get('minio.secretKey'),
    });
    this.bucket = this.configService.get('minio.bucket') || 'dmxk-files';

    // 确保 bucket 存在
    this.ensureBucketExists();
  }

  /**
   * 确保存储桶存在
   * 如果不存在则创建
   */
  private async ensureBucketExists() {
    try {
      const exists = await this.minioClient.bucketExists(this.bucket);
      if (!exists) {
        await this.minioClient.makeBucket(this.bucket, 'us-east-1');
        console.log(`✅ MinIO bucket "${this.bucket}" 创建成功`);

        // 设置为公开读（方便访问图片）
        const policy = {
          Version: '2012-10-17',
          Statement: [
            {
              Effect: 'Allow',
              Principal: { AWS: ['*'] },
              Action: ['s3:GetObject'],
              Resource: [`arn:aws:s3:::${this.bucket}/*`],
            },
          ],
        };
        await this.minioClient.setBucketPolicy(
          this.bucket,
          JSON.stringify(policy),
        );
      }
    } catch (error) {
      console.error('MinIO 初始化失败:', error);
    }
  }

  /**
   * 上传文件
   *
   * @param file Express.Multer.File 对象
   * @param folder 文件夹名称（如：products, avatars）
   * @returns 文件访问 URL
   */
  async uploadFile(file: Express.Multer.File, folder: string = 'misc') {
    // 1.验证文件
    if (!file) {
      throw new BadRequestException('文件不能为空');
    }

    // 2. 生成唯一文件名
    const ext = file.originalname.split('.').pop();
    const fileName = `${folder}/${Date.now()}-${uuidv4()}.${ext}`;

    try {
      // 3. 上传到 MinIO
      await this.minioClient.putObject(
        this.bucket,
        fileName,
        file.buffer,
        file.size,
        {
          'Content-Type': file.mimetype,
        },
      );

      // 4. 生成访问 URL
      const url = await this.getFileUrl(fileName);
      return url;
    } catch (error) {
      console.error('文件上传失败:', error);
      throw new BadRequestException('文件上传失败');
    }
  }

  /**
   * 获取文件访问 URL
   */
  async getFileUrl(fileName: string): Promise<string> {
    const endPoint = this.configService.get('minio.endPoint');
    const port = this.configService.get('minio.port');
    const useSSL = this.configService.get('minio.useSSL');

    const protocol = useSSL ? 'https' : 'http';
    const portStr = port === 80 || port === 443 ? '' : `:${port}`;

    return `${protocol}://${endPoint}${portStr}/${this.bucket}/${fileName}`;
  }

  /**
   * 批量上传文件
   */
  async uploadFiles(
    files: Express.Multer.File[],
    folder: string = 'misc',
  ): Promise<string[]> {
    const uploadPromises = files.map((file) => this.uploadFile(file, folder));
    return await Promise.all(uploadPromises);
  }

  /**
   * 删除文件
   */
  async deleteFile(fileName: string): Promise<void> {
    try {
      // 从 URL 中提取文件名
      if (fileName.includes(this.bucket)) {
        const parts = fileName.split(`${this.bucket}/`);
        fileName = parts[1];
      }

      await this.minioClient.removeObject(this.bucket, fileName);
    } catch (error) {
      console.error('文件删除失败:', error);
      throw new BadRequestException('文件删除失败');
    }
  }

  /**
   * 验证图片文件
   */
  validateImage(file: Express.Multer.File): boolean {
    const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
    const maxSize = 5 * 1024 * 1024; // 5MB

    if (!allowedTypes.includes(file.mimetype)) {
      throw new BadRequestException('只支持 JPG、PNG、GIF、WEBP 格式的图片');
    }

    if (file.size > maxSize) {
      throw new BadRequestException('图片大小不能超过 5MB');
    }

    return true;
  }

  /**
   * 验证压缩文件
   */
  validateArchive(file: Express.Multer.File): boolean {
    const allowedTypes = [
      'application/zip',
      'application/x-zip-compressed',
      'application/x-rar-compressed',
      'application/x-7z-compressed',
    ];
    const maxSize = 100 * 1024 * 1024; // 100MB

    if (!allowedTypes.includes(file.mimetype)) {
      throw new BadRequestException('只支持 ZIP、RAR、7Z 格式的压缩文件');
    }

    if (file.size > maxSize) {
      throw new BadRequestException('文件大小不能超过 100MB');
    }

    return true;
  }
}
